package com.ruoyi.system.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.mapper.VideoDataMapper;
import org.apache.shiro.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.VideoTaskMapper;
import com.ruoyi.system.domain.VideoData;
import com.ruoyi.system.domain.VideoTask;
import com.ruoyi.system.service.ITaskDataRelService;
import com.ruoyi.system.service.IVideoDataService;
import com.ruoyi.system.service.IVideoTaskService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;
import java.util.stream.Collectors; // 必须导入这个类

/**
 * 任务管理Service业务层处理
 * 
 * @author wsx
 * @date 2025-07-30
 */
@Service
public class VideoTaskServiceImpl implements IVideoTaskService {
    @Autowired
    private VideoTaskMapper videoTaskMapper;

    @Autowired
    private ITaskDataRelService taskDataRelService;

    @Autowired
    private IVideoDataService videoDataService;

    @Value("${ffmpeg.savePath}")
    private String localVideoDir;
    /**
     * 查询任务管理
     * 
     * @param taskId 任务管理主键
     * @return 任务管理
     */
    @Override
    public VideoTask selectVideoTaskByTaskId(Long taskId) {

        VideoTask videoTask = videoTaskMapper.selectVideoTaskByTaskId(taskId);
        if (videoTask != null) {
            videoTask.setDataIds(taskDataRelService.selectTaskDataIdsByTaskId(taskId));
        }
        return videoTask;
    }

    /**
     * 查询任务管理列表
     * 
     * @param videoTask 任务管理
     * @return 任务管理
     */
    @Override
    public List<VideoTask> selectVideoTaskList(VideoTask videoTask) {
        videoTask.setDelFlag("0");
        List<VideoTask> selectVideoTaskList = videoTaskMapper.selectVideoTaskList(videoTask);

        for (VideoTask videoTask2 : selectVideoTaskList) {
            long totalFileSizeByte = 0L; // 临时存储：总文件大小（字节，原始单位）
            // 1. 获取关联的视频数据ID和视频列表（原有逻辑）
            videoTask2.setDataIds(taskDataRelService.selectTaskDataIdsByTaskId(videoTask2.getTaskId()));

            if (videoTask2.getDataIds() == null || videoTask2.getDataIds().equals("")) {
                videoTask2.setIsArchived(0);
            } else {
                videoTask2.setIsArchived(1);

                List<VideoData> datalist = videoDataService.selectVideoDataListByIds(videoTask2.getDataIds(), new VideoData());
                // 2. 遍历视频数据，计算每个数据的文件大小并累加总字节数
                for (VideoData videoData2 : datalist) {
                    double storageSizeMb = 0.0;
                    double telemetrySizeMb = 0.0;

                    // 计算存储路径文件大小
                    String storagePath = videoData2.getStoragePath();
                    if (storagePath != null && !storagePath.trim().isEmpty()) {
                        File targetDir = new File(localVideoDir, storagePath);
                        File[] files = targetDir.listFiles();
                        if (files != null && files.length > 0) {
                            long storageSizeByte = 0L;
                            for (File file : files) {
                                if (file.isFile()) {
                                    storageSizeByte += file.length();
                                }
                            }
                            // 转换为MB并保留2位小数
                            storageSizeMb = storageSizeByte / (1024.0 * 1024.0);
                            storageSizeMb = Math.round(storageSizeMb * 100) / 100.0;
                            totalFileSizeByte += storageSizeByte;
                        }
                    }
                    // 赋值给storagePathFileSize属性
                    videoData2.setStoragePathFileSize(storageSizeMb);

                    // 计算遥测存储路径文件大小
                    String telemetryStoragePath = videoData2.getTelemetryStoragePath();
                    if (telemetryStoragePath != null && !telemetryStoragePath.trim().isEmpty()) {
                        File targetDir2 = new File(localVideoDir, telemetryStoragePath);
                        File[] files2 = targetDir2.listFiles();
                        if (files2 != null && files2.length > 0) {
                            long telemetrySizeByte = 0L;
                            for (File file : files2) {
                                if (file.isFile()) {
                                    telemetrySizeByte += file.length();
                                }
                            }
                            // 转换为MB并保留2位小数
                            telemetrySizeMb = telemetrySizeByte / (1024.0 * 1024.0);
                            telemetrySizeMb = Math.round(telemetrySizeMb * 100) / 100.0;
                            totalFileSizeByte += telemetrySizeByte;
                        }
                    }
                    // 赋值给telemetryStoragePathFileSize属性
                    videoData2.setTelemetryStoragePathFileSize(telemetrySizeMb);
                }

                // 3. 计算总文件大小（MB）并保留2位小数
                double totalFileSizeMb = totalFileSizeByte / (1024.0 * 1024.0);
                double totalFileSizeMbRounded = Math.round(totalFileSizeMb * 100) / 100.0;

                // 4. 设置MB单位的总大小
                videoTask2.setTotalFileSize(totalFileSizeMbRounded);
                videoTask2.setVideoDataList(datalist);
            }
        }
        return selectVideoTaskList;
    }

    /**
     * 工具2：文件大小格式化（字节 → B/KB/MB/GB，保留2位小数）
     */
    private String formatFileSize(long size) {
        if (size < 0) {
            return "0 B";
        }
        String[] units = {"B", "KB", "MB", "GB"};
        int unitIndex = (int) (Math.log10(size) / Math.log10(1024));
        unitIndex = Math.min(unitIndex, units.length - 1); // 避免超出单位范围
        double formattedSize = size / Math.pow(1024, unitIndex);
        return String.format("%.2f %s", formattedSize, units[unitIndex]);
    }

    /**
     * 新增任务管理
     * 
     * @param videoTask 任务管理
     * @return 结果
     */
    @Override
    public int insertVideoTask(VideoTask videoTask) {
        videoTask.setCreateTime(DateUtils.getNowDate());
        int insertVideoTaskId = videoTaskMapper.insertVideoTask(videoTask);
        if (videoTask.getDataIds() != null){
            taskDataRelService.saveTaskDataRel(videoTask.getTaskId(), videoTask.getDataIds());
        }
        return insertVideoTaskId;
    }

    /**
     * 修改任务管理
     * 
     * @param videoTask 任务管理
     * @return 结果
     */
    @Override
    public int updateVideoTask(VideoTask videoTask) {
        videoTask.setUpdateTime(DateUtils.getNowDate());
        int updateVideoTaskId = videoTaskMapper.updateVideoTask(videoTask);
//        taskDataRelService.saveTaskDataRel(videoTask.getTaskId(), videoTask.getDataIds());
        return updateVideoTaskId;
    }

    /**
     * 批量删除任务管理
     * 
     * @param taskIds 需要删除的任务管理主键
     * @return 结果
     */
    @Override
    public int deleteVideoTaskByTaskIds(String taskIds) {
        return videoTaskMapper.deleteVideoTaskByTaskIds(Convert.toStrArray(taskIds));
    }

    @Autowired
    private VideoDataMapper videoDataMapper;


    /**
     * 批量更新任务管理状态
     * 
     * @param taskIds 需要更新的任务管理主键集合
     * @return 结果
     */
    @Override
    public int updateDelFlag(String taskIds) {
        String[] strArray = Convert.toStrArray(taskIds);
        for (String str : strArray) {
            // 根据任务ID查询关联的数据ID列表
            List<Map<String, Object>> dataList = videoTaskMapper.selectAnaTaskDataRelByTaskId(Integer.parseInt(str));

            for (Map<String, Object> map : dataList) {
                Long dataId = Long.parseLong(map.get("data_id") + "");

                // 查询视频数据（校验存在性）
                VideoData videoData = videoDataMapper.selectVideoDataByDataId(dataId);
                if (videoData == null) {
                    System.err.println("视频数据不存在，dataId: "+ dataId);
                    continue;
                }

                // 路径处理：统一格式
                String storagePath = videoData.getStoragePath();
                String telemetryPath = videoData.getTelemetryStoragePath();

                System.err.println("/storagePath-------" + storagePath);

                List<String> deleteFailFiles = new ArrayList<>();

                // 处理视频存储路径
                if (StringUtils.hasText(storagePath)) {
                    // 统一分隔符为系统原生
                    String normalizedStoragePath = storagePath.replace("\\", File.separator)
                            .replace("/", File.separator);
                    // 去除开头多余的分隔符
                    if (normalizedStoragePath.startsWith(File.separator)) {
                        normalizedStoragePath = normalizedStoragePath.substring(1);
                    }

                    // 构建绝对路径
                    Path baseDirPath = Paths.get(localVideoDir);
                    Path absoluteStoragePathObj = baseDirPath.resolve(normalizedStoragePath);
                    String absoluteStoragePath = absoluteStoragePathObj.toString();

                    System.err.println("absoluteStoragePath（视频绝对路径）--------" + absoluteStoragePath);

                    // 删除视频目录
                    deleteDirWithForceRelease(new File(absoluteStoragePath), deleteFailFiles);
                } else {
                    System.err.println("storagePath为空，跳过视频文件删除");
                }

                // 处理遥测存储路径（增加null检查）
                String absoluteTelemetryStoragePath = null;
                if (StringUtils.hasText(telemetryPath)) {
                    // 统一telemetryPath的分隔符
                    String normalizedTelemetryPath = telemetryPath.replace("\\", File.separator)
                            .replace("/", File.separator);
                    // 拼接遥测根目录
                    String telemetryStoragePath = "telemetryStoragePath" + File.separator + normalizedTelemetryPath;
                    // 去除路径中可能的重复分隔符
                    telemetryStoragePath = telemetryStoragePath.replace(File.separator + File.separator, File.separator);

                    System.err.println("telemetryStoragePath（相对路径）--------" + telemetryStoragePath);

                    // 构建绝对路径
                    Path baseDirPath = Paths.get(localVideoDir);
                    Path absoluteTelemetryPathObj = baseDirPath.resolve(telemetryStoragePath);
                    absoluteTelemetryStoragePath = absoluteTelemetryPathObj.toString();

                    System.err.println("absoluteTelemetryStoragePath（遥测绝对路径）--------" + absoluteTelemetryStoragePath);
                } else {
                    System.err.println("telemetryPath为空，跳过遥测文件删除");
                }

                // 删除遥测目录（基于入参路径）
                if (StringUtils.hasText(absoluteTelemetryStoragePath)) {
                    deleteDirWithForceRelease(new File(absoluteTelemetryStoragePath), deleteFailFiles);
                }

                // 删除数据库中的数据记录
                int deleteCount = videoDataMapper.deleteVideoDataByDataId(dataId);

                // 处理删除失败的文件
                if (!deleteFailFiles.isEmpty()) {
                    System.err.println("删除文件失败列表："+ deleteFailFiles);
                    // 可以根据业务需求决定是否继续执行或抛出异常
                }
            }

            // 删除关联关系
            videoTaskMapper.deleteAnaTaskDataRelByTaskId(Integer.parseInt(str));

            // 删除任务
            videoTaskMapper.deleteVideoTaskByTaskId(Long.parseLong(str));
        }
        return strArray.length;
    }


    /**
     * 核心删除方法：强制删除目录（含内容），JDK 8 兼容
     * @param target 目标文件/目录
     * @param failList 失败记录列表
     */
    private void deleteDirWithForceRelease(File target, List<String> failList) {
        if (target == null || !target.exists()) {
            failList.add("目标不存在：" + (target != null ? target.getAbsolutePath() : "null"));
            return;
        }

        // 处理文件：重试删除（应对占用）
        if (target.isFile()) {
            boolean deleted = forceDeleteFile(target);
            if (deleted) {
                System.err.println("文件删除成功：" + target.getAbsolutePath());
            } else {
                failList.add("文件删除失败（已重试3次）：" + target.getAbsolutePath());
            }
            return;
        }

        // 处理目录：先删子内容，再删目录
        File[] childFiles = target.listFiles();
        if (childFiles == null) {
            failList.add("无法读取目录子内容（权限不足）：" + target.getAbsolutePath());
            return;
        }
        // 递归删除所有子内容
        for (File child : childFiles) {
            deleteDirWithForceRelease(child, failList);
        }

        // 删除空目录（重试）
        boolean dirDeleted = forceDeleteDir(target);
        if (dirDeleted) {
            System.err.println("目录删除成功：" + target.getAbsolutePath());
        } else {
            failList.add("目录删除失败（已重试3次）：" + target.getAbsolutePath());
        }
    }

    /**
     * 强制删除空目录（重试机制）
     * @param dir 目标目录
     * @return 是否删除成功
     */
    private boolean forceDeleteDir(File dir) {
        // 先确认目录为空
        if (dir.listFiles() != null && dir.listFiles().length > 0) {
            return false;
        }
        // 重试3次
        for (int i = 0; i < 3; i++) {
            try {
                if (dir.delete()) {
                    return true;
                }
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }
        return false;
    }

    /**
     * 强制删除文件（JDK 8 兼容，无 var 关键字）
     * @param file 目标文件
     * @return 是否删除成功
     */
    private boolean forceDeleteFile(File file) {
        // 重试3次，每次间隔1秒
        for (int i = 0; i < 3; i++) {
            try {
                // 释放文件资源（JDK 8 正确关闭流，无 var）
                releaseFileResource(file);
                // 执行删除
                if (file.delete()) {
                    return true;
                }
                // 等待1秒重试
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            } catch (Exception e) {
                continue; // 忽略临时异常
            }
        }
        return false;
    }

    /**
     * 释放文件资源（修复 Files.flush 错误，JDK 8 兼容）
     * @param file 目标文件
     */
    private void releaseFileResource(File file) {
        RandomAccessFile raf = null; // JDK 8 需显式声明类型，不能用 var
        try {
            // 打开文件后立即关闭，强制释放JVM持有的文件句柄
            raf = new RandomAccessFile(file, "r");
            raf.close(); // 显式关闭流
        } catch (IOException e) {
            // 忽略异常：说明文件未被JVM占用（可能是外部进程占用）
        } finally {
            // 确保流一定关闭（避免资源泄漏）
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    // 忽略关闭异常
                }
            }
        }
    }

    /**
     * 删除任务管理信息
     * 
     * @param taskId 任务管理主键
     * @return 结果
     */
    @Override
    public int deleteVideoTaskByTaskId(Long taskId) {
        return videoTaskMapper.deleteVideoTaskByTaskId(taskId);
    }

    @Override
    @Transactional  // 保证事务一致性
    public int importVideoTaskData(Map<String, Object> taskMap, List<Map<String, Object>> dataList) {
        // 1. 插入任务，获取自增task_id
        videoTaskMapper.insertTask(taskMap);
        Long taskId = (Long) taskMap.get("task_id");

        // 2. 批量插入数据，获取自增data_id（需注意：批量插入时selectKey无法直接返回列表，需通过其他方式获取）
        // 简化处理：假设dataList中已包含data_id，或通过循环插入单条获取（视数据库类型调整）
        videoTaskMapper.batchInsertData(dataList);

        // 3. 构建关联关系列表
        List<Map<String, Object>> relList = dataList.stream().map(data -> {
            Map<String, Object> rel = new HashMap<>();
            rel.put("task_id", taskId);
            rel.put("data_id", data.get("data_id"));  // 需确保data_id已正确获取
            return rel;
        }).collect(Collectors.toList());

        // 4. 批量插入关联关系
        videoTaskMapper.batchInsertTaskDataRel(relList);

        // 返回总处理条数（任务1条 + 数据N条）
        return 1 + dataList.size();
    }


    /**
     * 批量导入视频任务数据（事务保证：要么全成功，要么全失败）
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int batchImportVideoTaskData(List<Map<String, Object>> taskMapList,
                                        List<Map<String, Object>> joinList,
                                        List<Map<String, Object>> dataList,
                                        List<Map<String, Object>> telemetryList) {
        int totalCount = 0;

        // 1. 批量导入任务基本信息
        if (taskMapList != null && !taskMapList.isEmpty()) {
            // 先删除已存在的任务（可选：根据业务需求决定是否覆盖）
//            deleteExistingTasks(taskMapList);

            // 批量插入新任务
            int taskCount = videoTaskMapper.batchInsertTasks(taskMapList);
            totalCount += taskCount;
        }

        // 2. 批量导入任务关联信息
        if (joinList != null && !joinList.isEmpty()) {
            // 先删除关联信息（可选）
//            deleteExistingJoins(joinList);

            // 批量插入关联信息
            int joinCount = videoTaskMapper.batchInsertJoins(joinList);
            totalCount += joinCount;
        }

        // 3. 批量导入视频数据信息
        if (dataList != null && !dataList.isEmpty()) {
            // 先删除视频数据（可选）
//            deleteExistingData(dataList);

            // 批量插入视频数据
            int dataCount = videoTaskMapper.batchInsertData(dataList);
            totalCount += dataCount;
        }
        //4,批量导入遥测数据
        if (telemetryList != null && !telemetryList.isEmpty()) {

            //批量插入遥测数据
            int telemetryDataCount = videoTaskMapper.batchInsertTelemetryData(telemetryList);
            totalCount += telemetryDataCount;
        }

        return totalCount;
    }

    /**
     * 删除已存在的任务（根据task_id）
     */
    /**
     * 删除已存在的任务（根据task_id）
     */
    private void deleteExistingTasks(List<Map<String, Object>> taskMapList) {
        List<String> taskIds = taskMapList.stream()
                .map(task -> Objects.toString(task.get("task_id"), ""))
                .filter(id -> !id.isEmpty())
                .collect(Collectors.toList()); // 替换为 Collectors.toList()

//        if (!taskIds.isEmpty()) {
//            videoTaskMapper.batchDeleteTasks(taskIds);
//        }
    }

    /**
     * 删除已存在的关联信息（根据task_id）
     */
    private void deleteExistingJoins(List<Map<String, Object>> joinList) {
        List<String> taskIds = joinList.stream()
                .map(join -> Objects.toString(join.get("task_id"), ""))
                .filter(id -> !id.isEmpty())
                .distinct()
                .collect(Collectors.toList()); // 替换为 Collectors.toList()

//        if (!taskIds.isEmpty()) {
//            videoTaskMapper.batchDeleteJoinsByTaskIds(taskIds);
//        }
    }

    /**
     * 删除已存在的视频数据（根据task_id）
     */
    private void deleteExistingData(List<Map<String, Object>> dataList) {
        List<String> taskIds = dataList.stream()
                .map(data -> Objects.toString(data.get("task_id"), ""))
                .filter(id -> !id.isEmpty())
                .distinct()
                .collect(Collectors.toList());

//        if (!taskIds.isEmpty()) {
//            videoTaskMapper.batchDeleteDataByTaskIds(taskIds);
//        }
    }
}
